
import sun.misc.Cleaner;

import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.util.*;
import java.util.Date;

public class ServerSideImpl extends UnicastRemoteObject implements ServerSide{
    static List<Client> users = new ArrayList<Client>();

    protected HashMap<Client, String> clients = new HashMap<>();

    public ServerSideImpl() throws RemoteException {
    }

    public void hello(Client cm, String ctName, String saying, String mode) throws Exception {
        if (!users.contains(cm)) {
            users.add(cm);
        }

        if(saying.equals("logout")){
            logout(cm);
            return;
        }

        if(mode.equals(""))return;

        Client ct = new ClientImpl();
        Iterator iter = clients.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            if(entry.getValue().equals(ctName)){
                ct = (Client) entry.getKey();
            }
        }
//        try {
        java.util.Date now = new java.util.Date();
        String clientt = cm.toString();
        String msg = clientt + now + saying;
        //System.out.println(msg);
        Integer modeI = Integer.valueOf(mode);
        switch (modeI){
            case 1:
                postMessage(cm,saying);
                break;
            case 0:
                sendMessage(cm,ct,saying);
                break;
            default:
                break;
        }


//            for (Client c : users) {
//                c.showDialog(msg);
//            }
//        } catch (RemoteException ex) {
        //users.remove(cm);
//            ex.printStackTrace();
//        }
//    }
    }

    public void register(String name,Client client) throws RemoteException {
        System.out.println("Registry client ...");
        if(client.equals(null)) System.out.println("unknown client");

//        ClientImpl client1 = (ClientImpl)client;
        clients.put(client,name);

        System.out.println("Client: "+name+" registry successfully!");
        //System.out.println(clients.toString());
    }

    public void logout(Client client){
        try {
            String name = getNameByClient(client);
            System.out.println("Client "+name+" has logout!");
            clients.remove(client);
            client.exit();
        } catch (RemoteException e) {

        }
    }


    public void postMessage(Client cm,String content){
         Iterator iter = clients.entrySet().iterator();
        java.util.Date now = new java.util.Date();
        String sender;
         try{

             while(iter.hasNext()){
                 Map.Entry entry = (Map.Entry) iter.next();
                 Client client = (Client) entry.getKey();
                 //System.out.println("client name is: "+entry.getValue()+" ;client itself is "+entry.getKey());
                 if(entry.getKey().equals(cm)){
                     sender = entry.getValue().toString();
                     System.out.println("Client "+sender+" is boradcasting message...Content: "+content);
                     continue;
                 }
                 else {
                     String message = "Time: "+now+": From sender "+getNameByClient(cm)+": "+content;
                     client.showMessage(message);
                 }
        }

        }catch(Exception e){

             e.printStackTrace();
             System.err.println("Removing invalid client.");

             iter.remove();
        }
    }

    public void sendMessage(Client cm, Client ct, String content){
        Iterator iter = clients.entrySet().iterator();
        Date now = new Date();
        String sender=null;
        String receiver;
        try{

            while(iter.hasNext()){
                Map.Entry entry = (Map.Entry) iter.next();
                //Client client = (Client) entry.getKey();
                //System.out.println("client name is: "+entry.getValue()+" ;client itself is "+entry.getKey());
                if(entry.getKey().equals(cm)){
                    if(!clients.containsKey(ct)){
                        System.out.println("Client does not exist.");
                        Client sendClient = (Client)cm;
                        sendClient.showMessage("Reciver has logout; Can not deliver message");
                        return;
                    }
                    continue;
                }
                if(entry.getKey().equals(ct)){
                    Client receiverClient = (Client) ct;
                    receiver = entry.getValue().toString();
                    System.out.println("Client "+getNameByClient(cm)+" is sending to Client "+receiver+"; Content is "+content);
                    String message = "Time: "+now+": From sender "+getNameByClient(cm)+": "+content;
                    receiverClient.showMessage(message);
                    break;
                }
            }

        }catch(Exception e){

            e.printStackTrace();
            System.err.println("Removing invalid client.");

            iter.remove();
        }
    }

    public String getNameByClient(Client client){
        Iterator iter = clients.entrySet().iterator();
        while(iter.hasNext()){
            Map.Entry entry = (Map.Entry) iter.next();
            if(entry.getKey().equals(client)){
                return entry.getValue().toString();
            }
        }
        return "unknown sender";
    }

    public void registry(Client client) throws RemoteException{
    }

    private String message = "hello";

    private boolean status = true;

    private int n;

    void ClientNumber(){
        n++;
    }

    @Override
    public int getNumber() throws RemoteException{
        return n;
    }

    @Override
    public String getMessage() throws RemoteException{
        return message;
    }

    @Override
    public void setMessage(String message)throws RemoteException{
        this.message = message;
    }

    @Override
    public void setStatus(boolean status)throws RemoteException{
        this.status = status;
    }

    public boolean getStatus()throws RemoteException{
        return this.status;
    }



    public static void main(String args[]) throws Exception {
        LocateRegistry.createRegistry(1099);
        ServerSide remote = new ServerSideImpl();
        Naming.rebind("rmi://192.168.3.13:1099/jackyluo", remote);
        System.out.println("Server is ready...");
    }
}
